using Microsoft.AspNetCore.Components.Authorization;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Text.Json;
using Microsoft.IdentityModel.Tokens;
using HtERP.Data;

namespace HtERP.Services;

/// <summary>
/// 认证服务实现
/// </summary>
public class AuthService : IAuthService
    {
        private readonly AuthenticationStateProvider? _authenticationStateProvider;
        private readonly UserService _userService;
        private readonly ILogger _logger;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IConfiguration _configuration;
        private string _authToken = string.Empty;
        
        // 静态字段，用于存储当前用户的认证状态，绕过可能有问题的AuthenticationStateProvider
        private static ClaimsPrincipal _currentUser = new ClaimsPrincipal(new ClaimsIdentity());

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="authenticationStateProvider">认证状态提供器</param>
    /// <param name="userService">用户服务</param>
    /// <param name="logger">日志记录器</param>
    /// <param name="httpContextAccessor">HTTP上下文访问器</param>
    /// <param name="configuration">配置服务</param>
    public AuthService(AuthenticationStateProvider authenticationStateProvider, UserService userService, ILogger logger, IHttpContextAccessor httpContextAccessor, IConfiguration configuration)
        {
            _authenticationStateProvider = authenticationStateProvider;
            _userService = userService;
            _logger = logger;
            _httpContextAccessor = httpContextAccessor;
            _configuration = configuration;
            
            _logger.Log(LogLevel.Info, $"AuthService构造函数: _authenticationStateProvider类型={_authenticationStateProvider?.GetType().FullName}, 值={_authenticationStateProvider?.ToString()}");
        }

    /// <inheritdoc />
        public async Task<LoginResult> LoginAsync(string username, string password, bool saveCredentials = false)
        {
            var result = new LoginResult();
            _logger.Log(LogLevel.Info, $"用户登录请求: {username}, 是否保存凭据: {saveCredentials}");

            try
            {
                // 验证用户凭据
                var user = await _userService.ValidateUserCredentialsAsync(username, password);
                if (user == null)
                {
                    result.Success = false;
                    result.ErrorMessage = "用户名或密码错误";
                    _logger.Log(LogLevel.Warning, "用户登录失败: 凭据无效");
                    return result;
                }

                if (!user.IsActive)
                {
                    result.Success = false;
                    result.ErrorMessage = "用户已被禁用";
                    _logger.Log(LogLevel.Warning, "用户登录失败: 账户已禁用");
                    return result;
                }

                // 确定用户角色
                var role = user.Username.Equals("admin", StringComparison.OrdinalIgnoreCase) ? "Admin" : "User";

                // 创建ClaimsIdentity和ClaimsPrincipal确保认证状态被正确设置
                var claims = new List<Claim>
                {
                    new Claim(ClaimTypes.Name, user.Username),
                    new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
                    new Claim(ClaimTypes.Role, role),
                    new Claim("isWebUser", "true") // 添加标记区分网页用户
                };

                // 如果需要保存凭据，则调用保存凭据方法
                if (saveCredentials)
                {
                    await SaveCredentialsAsync(username, password);
                }

                // 所有操作完成后，设置认证状态
                // 更新静态字段中的认证状态
                _currentUser = new ClaimsPrincipal(new ClaimsIdentity(claims, "custom"));
                _logger.Log(LogLevel.Info, $"已设置静态用户认证状态: {user.Username}, 角色: {role}");

                // 设置认证状态到AuthenticationStateProvider
                if (_authenticationStateProvider is PersistingAuthenticationStateProvider authProvider)
                {
                    _logger.Log(LogLevel.Info, "直接调用PersistingAuthenticationStateProvider.SetAuthenticationStateAsync");
                    await authProvider.SetAuthenticationStateAsync(user.Username, user.Id.ToString(), role);
                }
                else
                {
                    // 如果类型检查失败，尝试使用as操作符转换，使用不同的变量名避免冲突
                    var asAuthProvider = _authenticationStateProvider as PersistingAuthenticationStateProvider;
                    if (asAuthProvider != null)
                    {
                        _logger.Log(LogLevel.Info, $"使用as操作符转换成功，调用SetAuthenticationStateAsync");
                        await asAuthProvider.SetAuthenticationStateAsync(user.Username, user.Id.ToString(), role);
                    }
                    else
                    {
                        // 如果仍然无法获取PersistingAuthenticationStateProvider实例，使用静态方法设置认证状态
                        _logger.Log(LogLevel.Warning, $"无法获取PersistingAuthenticationStateProvider实例，尝试使用静态方法设置认证状态，实际类型: {_authenticationStateProvider?.GetType().FullName}");
                        PersistingAuthenticationStateProvider.SetGlobalAuthenticationState(user.Username, user.Id.ToString(), role);
                    }
                }

                result.Success = true;
                result.Claims = claims;
                _logger.Log(LogLevel.Info, $"用户登录成功: {username}");

                return result;
            }
            catch (Exception ex)
            {
                _logger.Log(LogLevel.Error, $"用户登录异常: {username}", ex);
                result.Success = false;
                result.ErrorMessage = "登录过程中发生错误";
                return result;
            }
        }

        /// <summary>
        /// 获取或刷新WebAPI认证令牌（仅用于文件上传等需要WebAPI访问的功能）
        /// </summary>
        /// <returns>认证令牌</returns>
        public async Task<string> GetOrRefreshAuthTokenAsync()
        {
            // 如果令牌已经存在且未过期，直接返回
            if (!string.IsNullOrEmpty(_authToken) && !IsTokenExpired(_authToken))
            {
                _logger.Log(LogLevel.Info, "使用缓存的WebAPI认证令牌");
                return _authToken;
            }
        
            // 检查令牌是否过期的辅助方法
            bool IsTokenExpired(string token)
            {
                try
                {
                    if (string.IsNullOrEmpty(token))
                        return true;
                    
                    var tokenHandler = new JwtSecurityTokenHandler();
                    if (tokenHandler.CanReadToken(token))
                    {
                        var jwtToken = tokenHandler.ReadJwtToken(token);
                        return jwtToken.ValidTo < DateTime.UtcNow;
                    }
                    
                    // 如果无法解析为JWT令牌，使用简单的过期检查逻辑
                    // 这里只是一个简单的判断，实际上应该根据具体的令牌格式实现
                    return true;
                }
                catch (Exception ex)
                {
                    _logger.Log(LogLevel.Error, "检查令牌过期状态异常", ex);
                    return true; // 出错时默认认为令牌已过期
                }
            }

            try
            {
                // 从配置中获取WebAPI专用的用户名和密码
                var webApiUsername = _configuration["ApiSettings:WebApiUsername"];
                var webApiPassword = _configuration["ApiSettings:WebApiPassword"];

                if (!string.IsNullOrEmpty(webApiUsername) && !string.IsNullOrEmpty(webApiPassword))
                {
                    _logger.Log(LogLevel.Info, "使用配置中的WebAPI专用凭据获取认证令牌");
                    _authToken = await GetServerAuthToken(webApiUsername, webApiPassword);
                }

                if (string.IsNullOrEmpty(_authToken))
                {
                    // 如果无法获取WebAPI令牌，记录警告但不影响本地登录状态
                    _logger.Log(LogLevel.Warning, "无法获取WebAPI认证令牌");
                }
            }
            catch (Exception ex)
            {
                _logger.Log(LogLevel.Error, "获取WebAPI认证令牌异常", ex);
                // 异常不影响本地登录状态
            }

            return _authToken ?? string.Empty;
        }

        /// <summary>
        /// 向服务器发送登录请求获取认证令牌
        /// </summary>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        /// <returns>服务器返回的认证令牌</returns>
        private async Task<string> GetServerAuthToken(string username, string password)
        {
            try
            {
                _logger.Log(LogLevel.Info, "向服务器发送登录请求获取认证令牌");
                
                // 获取API基础URL
                var apiBaseUrl = _configuration["ApiSettings:ApiBaseUrl"] ?? "https://localhost:5001";
                
                // 创建HttpClientHandler并设置SSL证书验证回调
                var handler = new HttpClientHandler();
                // 忽略SSL证书验证（仅开发环境使用）
                handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
                
                using var httpClient = new HttpClient(handler);
                httpClient.DefaultRequestHeaders.Accept.Clear();
                httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
                
                // 构建请求URL
                var baseUrl = apiBaseUrl.TrimEnd('/');
                var requestUrl = baseUrl.EndsWith("/api") ? $"{baseUrl}/Auth/login" : $"{baseUrl}/api/Auth/login";
                
                // 构建请求内容
                var loginRequest = new { Identifier = username, Password = password };
                var jsonContent = JsonSerializer.Serialize(loginRequest);
                var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
                
                // 发送请求
                var response = await httpClient.PostAsync(requestUrl, content);
                
                if (response.IsSuccessStatusCode)
                {
                    var responseContent = await response.Content.ReadAsStringAsync();
                    var result = JsonDocument.Parse(responseContent);
                    
                    // 从响应中获取令牌
                    if (result.RootElement.TryGetProperty("token", out var tokenElement))
                    {
                        var token = tokenElement.GetString();
                        _logger.Log(LogLevel.Info, "成功获取服务器认证令牌");
                        return token ?? string.Empty;
                    }
                    else
                    {
                        _logger.Log(LogLevel.Warning, "服务器响应中未包含token字段");
                        return string.Empty;
                    }
                }
                else
                {
                    var errorContent = await response.Content.ReadAsStringAsync();
                    _logger.Log(LogLevel.Warning, $"服务器登录失败: {response.StatusCode}, {errorContent}");
                    return string.Empty;
                }
            }
            catch (Exception ex)
            {
                _logger.Log(LogLevel.Error, "服务器登录异常", ex);
                return string.Empty;
            }
        }

    /// <inheritdoc />
    public async Task LogoutAsync()
    {
        _logger.Log(LogLevel.Info, "用户注销请求");

        try
        {
            // 清除认证状态
            if (_authenticationStateProvider is PersistingAuthenticationStateProvider provider)
            {
                // 使用可用的ClearAuthenticationState方法
                await provider.ClearAuthenticationStateAsync();
            }

            // 清除Cookie或其他会话信息
            if (_httpContextAccessor.HttpContext != null)
            {
                // 清除所有会话数据，包括保存的凭据
                _httpContextAccessor.HttpContext.Session.Clear();
                _logger.Log(LogLevel.Info, "已清除会话数据和保存的凭据");
            }

            // 清除认证令牌
            _authToken = string.Empty;
            
            // 清除静态字段中的认证状态
            _currentUser = new ClaimsPrincipal(new ClaimsIdentity());
            _logger.Log(LogLevel.Info, "已清除静态字段中的认证状态");

            _logger.Log(LogLevel.Info, "用户注销成功");
        }
        catch (Exception ex)
        {
            _logger.Log(LogLevel.Error, "用户注销异常", ex);
        }
    }

    /// <inheritdoc />
        public async Task<CurrentUser> GetCurrentUserAsync()
        {
            try
            {
                // 优先使用静态字段获取认证状态，绕过可能有问题的AuthenticationStateProvider
                if (_currentUser?.Identity != null && _currentUser.Identity.IsAuthenticated)
                {
                    var static_userId = _currentUser.FindFirstValue(ClaimTypes.NameIdentifier) ?? string.Empty;
                    var static_username = _currentUser.FindFirstValue(ClaimTypes.Name) ?? string.Empty;
                    var static_roles = _currentUser.FindAll(ClaimTypes.Role).Select(c => c.Value).ToList();

                    // 如果角色列表为空，添加默认角色
                    if (static_roles.Count == 0)
                    {
                        static_roles.Add("User");
                    }

                    _logger.Log(LogLevel.Info, $"通过静态字段获取当前用户信息成功: 用户名={static_username}, 用户ID={static_userId}, 角色={string.Join(',', static_roles)}");
                    return new CurrentUser
                    {
                        UserId = static_userId,
                        Username = static_username,
                        Roles = static_roles,
                        IsAuthenticated = true
                    };
                }

                // 增加空引用检查，防止 _authenticationStateProvider 为空
                if (_authenticationStateProvider == null)
                {
                    _logger.Log(LogLevel.Warning, "_authenticationStateProvider 为空，无法获取当前用户信息");
                    return new CurrentUser { IsAuthenticated = false, ErrorMessage = "认证状态提供器不可用" };
                }
               
                // 如果静态字段没有认证信息，回退到使用AuthenticationStateProvider
                var authState = await _authenticationStateProvider.GetAuthenticationStateAsync();
                var user = authState.User;

                // 检查认证状态
                if (user.Identity == null || !user.Identity.IsAuthenticated)
                {
                    _logger.Log(LogLevel.Info, "当前用户未认证");
                    return new CurrentUser { IsAuthenticated = false };
                }

                // 获取用户信息
                var userId = user.FindFirstValue(ClaimTypes.NameIdentifier) ?? string.Empty;
                var username = user.FindFirstValue(ClaimTypes.Name) ?? string.Empty;
                var roles = user.FindAll(ClaimTypes.Role).Select(c => c.Value).ToList();

                // 如果角色列表为空，添加默认角色
                if (roles.Count == 0)
                {
                    roles.Add("User");
                }

                _logger.Log(LogLevel.Info, $"获取当前用户信息成功: 用户名={username}, 用户ID={userId}, 角色={string.Join(',', roles)}");
                return new CurrentUser
                {
                    UserId = userId,
                    Username = username,
                    Roles = roles,
                    IsAuthenticated = true
                };
            }
            catch (Exception ex)
            {
                _logger.Log(LogLevel.Error, "获取当前用户信息异常", ex);
                return new CurrentUser { IsAuthenticated = false, ErrorMessage = "获取用户信息失败" };
            }
        }

    /// <inheritdoc />
    public async Task<bool> IsAuthenticatedAsync()
    {
        try
        {
            var currentUser = await GetCurrentUserAsync();
            return currentUser.IsAuthenticated;
        }
        catch (Exception ex)
        {
            _logger.Log(LogLevel.Error, "检查用户认证状态异常", ex);
            return false;
        }
    }

    /// <inheritdoc />
    public async Task<bool> IsInRoleAsync(string role)
    {
        try
        {
            var currentUser = await GetCurrentUserAsync();
            return currentUser.IsAuthenticated && currentUser.Roles.Contains(role, StringComparer.OrdinalIgnoreCase);
        }
        catch (Exception ex)
        {
            _logger.Log(LogLevel.Error, $"检查用户角色异常: {role}", ex);
            return false;
        }
    }

    /// <inheritdoc />
    public async Task<LoginResult> LoginWithSavedCredentialsAsync()
    {
        var result = new LoginResult();
        _logger.Log(LogLevel.Info, "尝试使用保存的凭据登录");

        try
        {
            // 在实际应用中，这里应该从安全存储中获取保存的凭据
            // 这里仅作为示例实现
            if (_httpContextAccessor.HttpContext != null && _httpContextAccessor.HttpContext.Session.Keys.Contains("Username") &&
                _httpContextAccessor.HttpContext.Session.Keys.Contains("Password"))
            {
                var username = _httpContextAccessor.HttpContext.Session.GetString("Username");
                var password = _httpContextAccessor.HttpContext.Session.GetString("Password");

                if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
                {
                    return await LoginAsync(username, password);
                }
            }

            result.Success = false;
            result.ErrorMessage = "没有找到保存的凭据";
            _logger.Log(LogLevel.Warning, "没有找到保存的凭据");
            return result;
        }
        catch (Exception ex)
        {
            _logger.Log(LogLevel.Error, "使用保存的凭据登录异常", ex);
            result.Success = false;
            result.ErrorMessage = "自动登录过程中发生错误";
            return result;
        }
    }

    /// <inheritdoc />
    public string GetAuthToken()
    {
        _logger.Log(LogLevel.Info, "获取认证令牌");
        return _authToken;
    }

    /// <inheritdoc />
    public async Task<bool> SaveCredentialsAsync(string username, string password)
    {
        try
        {
            _logger.Log(LogLevel.Info, "尝试保存用户凭据");
            
            if (_httpContextAccessor.HttpContext == null)
            {
                _logger.Log(LogLevel.Warning, "HTTP上下文为空，无法保存凭据");
                return false;
            }
            
            // 将凭据保存到会话中
            _httpContextAccessor.HttpContext.Session.SetString("Username", username);
            _httpContextAccessor.HttpContext.Session.SetString("Password", password);
            
            _logger.Log(LogLevel.Info, "用户凭据保存成功");
            // 添加一个异步等待以消除警告
            await Task.CompletedTask;
            return true;
        }
        catch (Exception ex)
        {
            _logger.Log(LogLevel.Error, "保存用户凭据异常", ex);
            return false;
        }
    }

    /// <summary>
    /// 生成JWT认证令牌
    /// 与WebApi保持一致的令牌生成方式
    /// </summary>
    /// <param name="user">用户信息</param>
    /// <returns>JWT认证令牌</returns>
    private string GenerateJwtToken(User user)
    {
        try
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            // 获取与WebApi相同的JWT密钥
            var key = Encoding.ASCII.GetBytes(_configuration["Jwt:Key"] ?? "YourJwtSecretKeyThatIsAtLeast32CharactersLong");
            
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new[]
                {
                    new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
                    new Claim(ClaimTypes.Name, user.Username),
                    new Claim(ClaimTypes.Role, "User"), // 默认为User角色
                    new Claim("Email", user.Email ?? string.Empty)
                }),
                Expires = DateTime.UtcNow.AddMinutes(int.Parse(_configuration["Jwt:ExpiresInMinutes"] ?? "30")),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
                Issuer = _configuration["Jwt:Issuer"],
                Audience = _configuration["Jwt:Audience"]
            };

            var token = tokenHandler.CreateToken(tokenDescriptor);
            var jwtToken = tokenHandler.WriteToken(token);
            
            _logger.Log(LogLevel.Info, "成功生成JWT令牌");
            return jwtToken;
        }
        catch (Exception ex)
        {
            _logger.Log(LogLevel.Error, "生成JWT令牌失败", ex);
            // 如果生成JWT令牌失败，回退到简单的令牌生成方式
            return GenerateSimpleAuthToken(user.Username);
        }
    }
    
    /// <summary>
    /// 生成简单的认证令牌（仅作为JWT生成失败的回退方案）
    /// </summary>
    /// <param name="username">用户名</param>
    /// <returns>认证令牌</returns>
    private string GenerateSimpleAuthToken(string username)
    {
        try
        {
            var tokenData = new
            {
                Username = username,
                Timestamp = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss")
            };
            
            var json = JsonSerializer.Serialize(tokenData);
            var token = Convert.ToBase64String(Encoding.UTF8.GetBytes(json));
            
            _logger.Log(LogLevel.Info, "简单认证令牌生成成功");
            return token;
        }
        catch (Exception ex)
        {
            _logger.Log(LogLevel.Error, "简单认证令牌生成失败", ex);
            return string.Empty;
        }
    }
}